﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System.IO;
using Microsoft.Xna.Framework.Media;

namespace FierceWar
{
	public class PlayingScreen : Screen
	{
        private List<ElementalModel> _models = new List<ElementalModel>();
        private List<ElementalModel> _roads = new List<ElementalModel>();

        private ChaseCamera _camera;
        private Ship        _ship;
        private GameLevel   _gameLevel;

        private bool _cameraSpringEnabled = true;

		private List<int> _mapIndexes = new List<int>();
		private List<string> _maps = new List<string>();
		private Random _random = new Random();

		private BoundingBoxTree _bbt;
        private BoundingBoxTree _bbtEnemy;

		public bool IsMouseVisible = true;

        public PlayingScreen(GameResources resources, List<EventHandler> screenEvents)
            : base(resources, screenEvents)
        {
			// Setup camera.
			_camera = new ChaseCamera();
			_camera.AspectRatio = (float)resources.GraphicsDevice.Viewport.Width /
								  (float)resources.GraphicsDevice.Viewport.Height;
            Reset();
        }

		public override void PlayMusic()
		{
			base.PlayMusic();
			MediaPlayer.Volume = 1.0f;
			MediaPlayer.Play(Resources.PlayingBackground);
		}

		public override void Reset()
		{
			base.Reset();

			_bbt = new BoundingBoxTree(
				new Vector3(-65536.0f, 0.0f, -65536.0f),
				new Vector3(65536.0f, 131072.0f, 65536.0f));

            _bbtEnemy = new BoundingBoxTree(
                new Vector3(-65536.0f, 0.0f, -65536.0f),
                new Vector3(65536.0f, 131072.0f, 65536.0f));

            _gameLevel = new GameLevel(0, Resources);

            foreach (Enemy enemy in _gameLevel._enemies)
            {
                _bbtEnemy.Insert(enemy);
            }

            _ship = new Ship(Resources, Resources.GraphicsDevice,
                Resources.Content, ModelType.Ship2, _bbt, _bbtEnemy, _gameLevel._enemies);

			LoadRandomMap();

			if (_models.Count == 0)
			{
				_models.Add(new ElementalModel(Resources.Content, ModelType.Ground));
			}

			_camera.DesiredPositionOffset = new Vector3(0.0f, 2000.0f, 2000.0f);
			_camera.LookAtOffset = new Vector3(0.0f, 0.0f, -1200.0f);
			_cameraSpringEnabled = true;

			IsMouseVisible = true;
			_camera.IsFPSCamera = false;
			_ship.IsFPSCamera = false;

			UpdateCameraChaseTarget();

			_ship.Reset();
			_camera.Reset();
		}

        #region Load Map
		public void LoadMap(string fileName)
		{
			StreamReader sr = null;
			try
			{
				sr = File.OpenText("Map/" + fileName);
				_models.Clear();
				_roads.Clear();
				string line = null;
				while ((line = sr.ReadLine()) != null)
				{
					string[] values = (line.TrimEnd()).Split(new char[] { ' ' });

					// Check valid input string.
					if (values.Length < 10)
					{
						for (int i = values.Length; i <= 10; i++)
						{
							values[i] = "0";
						}
					}

					// Load type of model.
					int type = Convert.ToInt32(values[0]);
					// Create new model.
					ElementalModel model = new ElementalModel(Resources.Content,
						(ModelType)type);
					// Load model's position.
					model.Position = new Vector3((float)Convert.ToDouble(values[1]),
						(float)Convert.ToDouble(values[2]),
						(float)Convert.ToDouble(values[3]));
					// Load model's scale vector.
					model.Scale = new Vector3((float)Convert.ToDouble(values[4]),
						(float)Convert.ToDouble(values[5]),
						(float)Convert.ToDouble(values[6]));
					// Load model's rotation vector.
					model.Rotation = new Vector3((float)Convert.ToDouble(values[7]),
						(float)Convert.ToDouble(values[8]),
						(float)Convert.ToDouble(values[9]));
					// Now, the model was placed.
					model.IsPlaced = true;

					// Add the model into list.
					// Check type first.
					if (model.Type == ModelType.Road)
					{
						_roads.Add(model);
					}
					else
					{
						if (values.Length > 10)
						{
							for (int i = 10; i < values.Length; i++)
							{
								int index = Convert.ToInt32(values[i]);
								model.BoundingBoxMasterIndexes.Add(index);
								_bbt.Leave[index].Models.Add(model);
							}
						}
						_models.Add(model);
					}
				}

				sr.Close();
			}
			catch
			{
				return;
			}
		}

		private void LoadRandomMap()
		{
			if (_mapIndexes.Count == 0)
			{
				ReloadMapsList();
			}
			LoadMap(NextMap());
		}

		private string NextMap()
		{
			int mapIdx = _random.Next(_mapIndexes.Count);
			string mapPath = _maps[_mapIndexes[mapIdx]];
			_mapIndexes.RemoveAt(mapIdx);

			return mapPath;
		}

		private void ReloadMapsList()
		{
			_mapIndexes.Clear();
			_maps.Clear();

			System.IO.Directory.CreateDirectory("Map");
			string[] filePaths = Directory.GetFiles("Map/", "*.bsp");
			for (int i = 0; i < filePaths.Length; i++)
			{
				_maps.Add(Path.GetFileName(filePaths[i]));
				_mapIndexes.Add(i);
			}
		}
        #endregion

        public override void Update(GameTime gameTime)
        {
            // Toggle the camera spring on or off.
            if (KeyboardInput.IsKeyPressed(Keys.Enter) &&
				!_camera.IsFPSCamera)
            {
                _cameraSpringEnabled = !_cameraSpringEnabled;
            }

			if (MouseInput.IsRightClick)
			{
				_camera.IsFPSCamera = !_camera.IsFPSCamera;
				_ship.IsFPSCamera = !_ship.IsFPSCamera;
			}

			if (KeyboardInput.IsKeyDown(Keys.S))
			{
				_camera.Damping = 1500.0f;
			}
			else if (KeyboardInput.IsKeyUp(Keys.S))
			{
				_camera.Damping = 600.0f;
			}

            // Reset.
			if (KeyboardInput.IsKeyPressed(Keys.R))
            {
                _ship.Reset();
                _camera.Reset();
            }

			if (_camera.IsFPSCamera)
			{
				int centerX = Resources.GraphicsDevice.Viewport.Width / 2;
				int centerY = Resources.GraphicsDevice.Viewport.Height / 2;
				Mouse.SetPosition(centerX, centerY);

				_ship.Rotation.X +=
					MathHelper.ToRadians((centerY - MouseInput.LastState.Y) * 0.1f);
				_ship.Rotation.Y +=
					MathHelper.ToRadians((centerX - MouseInput.LastState.X) * 0.1f);

				IsMouseVisible = false;

				_camera.DesiredPositionOffset = new Vector3(0.0f, 0.0f, -1050.0f);
			}
			else
			{
				IsMouseVisible = true;

				_camera.DesiredPositionOffset = new Vector3(0.0f, 2000.0f, 2000.0f);
			}

            foreach (Enemy enemy in _gameLevel._enemies)
            {
                enemy.Update();
                _bbtEnemy.Remove(enemy);
                _bbtEnemy.Insert(enemy);
            }

			Vector3 tmpPosition = _ship.Position;

            if (_ship.Update(gameTime) == false)
            {
                _gameLevel.NextLevel();
                _ship.Enemies = _gameLevel._enemies;
                _ship.Level++;
				Resources.LevelUp.Play();
            }

            if (_bbt.HasCollision(_ship) || _bbtEnemy.HasCollision(_ship))
			{
				_ship.Position = tmpPosition - _ship.CurrentDirection * 100.0f;
				_ship.Velocity = -_ship.Direction * 100;
			}

            UpdateCameraChaseTarget();

            if (_cameraSpringEnabled && !_camera.IsFPSCamera)
            {
                _camera.Update(gameTime);
            }
            else
            {
                _camera.Reset();
            }

			// Pause.
            if (KeyboardInput.IsKeyPressed(Keys.P))
            {
                ScreenEvents[0].Invoke(this, new EventArgs());
            }

			// Quit.
            if (KeyboardInput.IsKeyPressed(Keys.Escape))
            {
                ScreenEvents[1].Invoke(this, new EventArgs());
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            base.Draw(gameTime);

            Resources.GraphicsDevice.BlendState = BlendState.Opaque;
            Resources.GraphicsDevice.DepthStencilState = DepthStencilState.None;
            Resources.GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            Resources.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;

            // Draw the ground.
            _models[0].Draw(_camera.View, _camera.Projection, _camera.Position);

            // Draw road.
            foreach (ElementalModel road in _roads)
            {
                road.Draw(_camera.View, _camera.Projection, _camera.Position);
            }

            // Draw other models.
            Resources.GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            for (int i = 1; i < _models.Count; i++)
            {
                _models[i].Draw(_camera.View, _camera.Projection, _camera.Position);
            }

			_ship.Draw(_camera.View, _camera.Projection, _camera.Position, gameTime);
            
            foreach (Enemy enemy in _gameLevel._enemies)
            {
                enemy.Draw(_camera.View, _camera.Projection, _camera.Position);
            }
        }

        private void UpdateCameraChaseTarget()
        {
            _camera.ChasePosition = _ship.Position;
            _camera.ChaseDirection = _ship.Direction;
            _camera.Up = _ship.Up;
        }
	}
}
